package com.cqgc.shiro;

import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.cqgc.pojo.entity.User;
import com.cqgc.service.UserService;
import com.cqgc.utils.JwtUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
public class MyRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    @Autowired
    private StringRedisTemplate redisTemplate;

    //根据token判断此Authenticator是否使用该realm
    //必须重写不然shiro会报错
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken;
    }
    /**
     * 只有当需要检测用户权限的时候才会调用此方法，例如@RequiresRoles,@RequiresPermissions之类的
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("授权~~~~~");
        //1. 根据accessToken，查询用户信息
        User user = (User) principals.getPrimaryPrincipal();
        List<String> roles = userService.getUserRoleInfoMapper(user.getUid());
        System.out.println("roles:" + roles);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        List<String> permissions = userService.getUserPermissionInfoMapper(roles);
        info.addRoles(roles);
        for (String permission : permissions) {
            info.addStringPermission(permission);
        }
        return info;
    }
    /**
     * 默认使用此方法进行用户名正确与否验证，错误抛出异常即可，在需要用户认证和鉴权的时候才会调用
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
        System.out.println("认证~~~~~~~");
        JWTToken token = (JWTToken) auth;
        String jwtToken = (String) token.getCredentials();
        DecodedJWT decode = JWT.decode(jwtToken);
        Claim claims = decode.getClaim("claims");
        Map<String, Object> map = claims.asMap();
        int uid = (int) map.get("uid");
        String account = (String) map.get("account");
        User user = userService.findByUser(uid);
        //2.若用户不存在, 则可以抛出 UnknownAccountException 异常
        if (user == null) {
            throw new AuthenticationException("用户不存在");
        }
        //3.token失效
        String redisToken = redisTemplate.opsForValue().get(account + "token");
        Long expire = redisTemplate.getExpire(account + "token");
        //当前时间
        Date nowDate = new Date();
        //过期时间
        Date expireDate = new Date(nowDate.getTime() + expire * 1000);
        if (redisToken == null || expireDate.before(nowDate)) {
            throw new IncorrectCredentialsException("token失效，请重新登录");
        }
        //获取已经登陆的用户
        User user1 = (User) SecurityUtils.getSubject().getPrincipal();
        return new SimpleAuthenticationInfo(user, jwtToken, getName());
    }

}
